#include <stdio.h>
#include <string.h>

void strlen_test();
void strcat_test();
void strncat_test();
void strcmp_test();
void strncmp_test();
void strcpy_test();
void strncpy_test();
void strchr_test();
void strstr_test();
void strtok_test();

int main(void) {
    //1.字符串实际长度
    strlen_test();              //len: length

    //2.字符串追加
    strcat_test();              //cat: concat
    //3.字符串有限追加
    strncat_test();

    //4.字符串比较
    strcmp_test();              //cmp: compare
    //5.字符串有限比较
    strncmp_test();

    //6.字符串拷贝
    strcpy_test();              //cpy: copy
    //7.字符串有限拷贝
    strncpy_test();

    //8.查找字符,返回字符所在指针
    strchr_test();              //chr: character
    //9.查找子串,返回字符串所在指针
    strstr_test();              //str: string

    //10.分割字符串
    strtok_test();              //tok: ???

    return 0;
}

/**
 * 1.返回字符串实际长度, 不包含字符串结尾的 0
 *   strlen: 只适用于 "不包含中文" 的 "字符串", "不适用于纯数组".
 */
void strlen_test() {
    char arr1[] = {'A', 'B', 'C', 'D', 'E'};   //纯数组, 不能用 strlen()
    char arr2[] = {'A', 'B', 'C', 'D', 'E', 0};//0结尾, 字符数组, 正常
    char arr3[100] = "hello world";
    char *str1 = "Hello World";              //字符串常量是以'\0'结尾!!!★★★(Visual Studio把鼠标放在右侧字符串上, 就能看出来)
    char* str2 = "Hello撒地方";               //有汉字, 不能用 strlen()

    printf("strlen(arr1) = %d\n", strlen(arr1));//17, 纯数组, 结果错误!!!
    printf("strlen(arr2) = %d\n", strlen(arr2));//5
    printf("sizeof(arr2) = %d\n", sizeof(arr3));//100
    printf("strlen(arr2) = %d\n", strlen(arr3));//11
    printf("strlen(str1) = %d\n", strlen(str1));//11
    printf("strlen(str2) = %d\n", strlen(str2));//11, 有汉字, 结果错误!!!
    //字符串以 0 结尾, 可以这样遍历
    while (*str1) {
        printf("%c", *str1++);                  //Hello World
    }
    puts("");
}

/**
 * 2.字符串追加, 将arr2 添加到 arr1中.
 *   存在缓冲区溢出问题(array 长度有可能不够), 会报错: C4996
 */
void strcat_test() {
    char array[100] = "hello world";
    char array1[]   = "abcde";
    //size_t strcat(char * _Str1, const char * _Str2);
    strcat(array, array1);
    printf("array = %s\n", array);              //hello worldabcde
}

/**
 * 3.字符串有限追加, 参3: 最多还能追加多少个字符
 */
void strncat_test() {
    char arr0[100] = "hello world";
    char arr1[] = "abcde";
    /**
     * size_t strncat(char * _Str1, const char * _Str2, size_t len);
     * array 后面最多还能追加3个字符
     */
    strncat(arr0, arr1, 3);
    printf("arr0 = %s\n", arr0);                //hello worldabc
}

/**
 * 4.字符串比较
 */
void strcmp_test() {
    char* str0 = "Hello撒地方";
    char* str1 = "Hello撒地方";
    char arr0[100] = "hello world";
    char arr1[100] = "hello";
    char arr2[]    = "hello\0abc";
    char arr3[]    = "hello\0abc";
    char arr4[]    = "hello\0def";
    int re1 = str0 == str1;         //可以, 因为这2个字符串都是常量
    int re2 = arr0 == arr1;         //数组 不可以通过==来比较

    /**
     * int strcmp(const char * _Str1, const char * _Str2);
     * 返回值:
     *  =0: 相等
     *  >0: 不同操作系统返回的结果不同, 有的返回差值, 有的返回±1
     *  <0:
     */
    int re3 = strcmp(arr0, arr1);
    int re4 = strcmp(arr2, arr3);
    int re5 = strcmp(arr3, arr4);           //re1 = 1, re2 = 0, re3 = 1, re4 = 0, re5 = 0
    printf("re1 = %d, re2 = %d, re3 = %d, re4 = %d, re5 = %d\n", re1, re2, re3, re4, re5);
}

/**
 * 5.字符串有限比较
 */
void strncmp_test() {
    char arr0[100] = "hello world";
    char arr1[]    = "hello";
    //只比较前5个字符
    int re6 = strncmp(arr0, arr1, 5);
    printf("re6 = %d\n", re6);          //0
}

/**
 * 6.字符串拷贝, 将参数 _Str2 拷贝到 _Str1 中
 */
void strcpy_test() {
    char arr0[100] = "hello world";
    char arr1[]    = "abcde";
    char arr2[]    = "hijkl mnopq rstuvw";
    /**
     * char * strcpy(char * _Str1, const char * _Str2);
     */
    strcpy(arr0, arr1);
    printf("拷贝后arr0 = %s\n", arr0);   //abcde
    strcpy(arr0, arr2);
    printf("拷贝后arr0 = %s\n", arr0);   //hijkl mnopq rstuvw
}

/**
 * 7.字符串有限拷贝
 */
void strncpy_test() {
    char arr0[100] = "hello world";
    char arr1[]    = "abcde";
    char arr2[]    = "hijkl mnopq rstuvw";
    /**
     * 将arr1中前3位拷贝到arr0中的前3位
     * 例: strncpy(123456, abcdef, 3);   //abc456
     */
    strncpy(arr0, arr1, 3);
    printf("拷贝后arr0 = %s\n", arr0);   //abclo world
    strncpy(arr0, arr2, 3);
    printf("拷贝后arr0 = %s\n", arr0);   //hijlo world
}

/**
 * 8.查找字符,返回字符所在指针. 如果没有, 返回 NULL
 */
void strchr_test() {
    char array[100] = "hello world";
    //char * strchr(char * _Str, int _Ch);
    const char *buf = strchr(array, 'o');
    printf("%s\n", buf);    //o world
}

/**
 * 9.查找子串,返回字符串所在指针. 如果没有, 返回 NULL
 */
void strstr_test() {
    char array[100] = "hello world";
    //char * strshr(char * _Str, const char * _SubStr);
    const char *buf = strstr(array, "llo");
    printf("%s\n", buf);    //llo world
}

/**
 * 10.分割字符串 https://www.bilibili.com/video/BV1vs411n7TH?p=87
 *    strtok: 字符串截取, 会破坏原字符串, 用'\0'替换分割的标志位.
 */
void strtok_test() {
    char array[100] = "你好啊, he,llo, 世界!";
    //第1次调用, 参1是字符串
    char *p = strtok(array, ",");
    printf("&array = %p, &p = %p\n", array, p); //相同的地址!!!
    printf("array = %s, p = %s\n", array, p);   //你好啊, 你好啊
    while(p) {
        /**
         * 打印结果:
         *      "你好啊"
         *      " he"
         *      "llo"
         *      " 世界!"
         */
        printf("%s\n", p);
        //不是第1次调用, 参1是 NULL, 从缓冲区读取, 线程不安全!!!
        p = strtok(NULL, ",");
    }
}
